package com.syp.test.clustercacheflush.service;

import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.syp.test.clustercacheflush.dao.TaskRepository;
import com.syp.test.clustercacheflush.domain.TaskEntity;
import com.syp.test.clustercacheflush.util.Constants;

/**
 * 
 * @author syp
 * @update 2016年7月14日 下午8:39:35
 */
@Service("taskService")
public class TaskService {

	@Autowired
	protected TaskRepository taskRepository;

	/**
	 * 查询任务
	 *
	 * @param apply
	 * @return
	 */
	@Transactional(rollbackFor = { RuntimeException.class })
	public TaskEntity getByUuid(String uuid) {
		return this.taskRepository.getByUuid(uuid);
	}
	
	/**
	 * 根据uuid查询任务列表
	 * @param uuidList
	 * @return
	 */
	public List<TaskEntity> getListByUuidList(List<String> uuidList) {
		return this.taskRepository.getListByUuid(uuidList);
	}

	/**
	 * 保存任务
	 *
	 * @param apply
	 * @return
	 */
	@Transactional(rollbackFor = { RuntimeException.class })
	public void save(TaskEntity task) {
		this.taskRepository.save(task);
	}

	/**
	 * 批量保存任务
	 *
	 * @param apply
	 * @return
	 */
	@Transactional(rollbackFor = { RuntimeException.class })
	public void batchSave(List<TaskEntity> list) {
		/* 保存申请单 */
		this.taskRepository.save(list);
	}

	/**
	 * 锁定任务
	 * 
	 * @param id
	 * @return
	 * @throws Exception
	 */
	@Transactional(rollbackFor = { RuntimeException.class })
	public boolean lock(TaskEntity task) {
		long id = task.getId();
		int oldStatus = TaskStatus.INITIALIZE.getStatus();
		int newStatus = TaskStatus.LOCK.getStatus();
		int retryCount = task.getRetryCount();
		Date bizTime = task.getBizTime();
		Date lastUpdate = Calendar.getInstance().getTime();
		int influenceCount = taskRepository.safeUpdate(id, oldStatus, newStatus, retryCount, bizTime, lastUpdate);
		return influenceCount > 0 ? true : false;
	}

	/**
	 * 完成任务
	 * 
	 * @param id
	 * @return
	 * @throws Exception
	 */
	@Transactional(rollbackFor = { RuntimeException.class })
	public boolean finish(TaskEntity task) {
		long id = task.getId();
		int oldStatus = TaskStatus.LOCK.getStatus();
		int newStatus = TaskStatus.FINISH.getStatus();
		int retryCount = task.getRetryCount();
		Date bizTime = Calendar.getInstance().getTime();
		Date lastUpdate = Calendar.getInstance().getTime();
		int influenceCount = taskRepository.safeUpdate(id, oldStatus, newStatus, retryCount, bizTime, lastUpdate);
		return influenceCount > 0 ? true : false;
	}

	@Transactional(rollbackFor = { RuntimeException.class })
	public boolean unlock(TaskEntity task) {
		long id = task.getId();
		int oldStatus = TaskStatus.LOCK.getStatus();
		int newStatus = TaskStatus.INITIALIZE.getStatus();
		int retryCount = task.getRetryCount() + 1;
		Date bizTime = Calendar.getInstance().getTime();
		Date lastUpdate = Calendar.getInstance().getTime();
		int influenceCount = taskRepository.safeUpdate(id, oldStatus, newStatus, retryCount, bizTime, lastUpdate);
		return influenceCount > 0 ? true : false;
	}

	@Transactional(rollbackFor = { RuntimeException.class })
	public int unlock(List<TaskEntity> taskList) {
		List<Long> idList = new LinkedList<Long>();
		taskList.forEach(task->{
			idList.add(task.getId());
		});
		int oldStatus = TaskStatus.LOCK.getStatus();
		int newStatus = TaskStatus.INITIALIZE.getStatus();
		int increase = 1;
		Date bizTime = Calendar.getInstance().getTime();
		Date lastUpdate = Calendar.getInstance().getTime();
		int influenceCount = taskRepository.batchSafeUpdate(idList, oldStatus, newStatus, increase, bizTime, lastUpdate);
		return influenceCount;
	}

	public List<TaskEntity> getWaitToProcessTask() {
		Specification<TaskEntity> spec = new Specification<TaskEntity>() {
			public Predicate toPredicate(Root<TaskEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate[] pl = new Predicate[2];

				pl[0] = cb.equal(root.get("taskStatus"), TaskStatus.INITIALIZE.getStatus());
				pl[1] = cb.lessThan(root.get("bizTime"), Calendar.getInstance().getTime());
				return cb.and(pl);
			}
		};
		Pageable pageable = new PageRequest(0, Constants.HUNDRED_PAGE_SIZE);
		Page<TaskEntity> page = taskRepository.findAll(spec, pageable);
		return page.getContent();
	}

	public List<TaskEntity> getRetryFailureTask() {
		Specification<TaskEntity> spec = new Specification<TaskEntity>() {
			public Predicate toPredicate(Root<TaskEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate[] pl = new Predicate[3];

				pl[0] = cb.equal(root.get("taskStatus"), TaskStatus.LOCK.getStatus());
				pl[1] = cb.lessThan(root.get("lastUpdate"), DateTime.now().minusMinutes(5).toDate());
				pl[2] = cb.lessThan(root.get("retryCount"), Constants.TASK_MAX_RETRY_COUNT);
				return cb.and(pl);
			}
		};
		Pageable pageable = new PageRequest(0, Constants.HUNDRED_PAGE_SIZE);
		Page<TaskEntity> page = taskRepository.findAll(spec, pageable);
		return page.getContent();
	}

	public List<TaskEntity> getRetryFailureTask(Integer taskType) {
		Specification<TaskEntity> spec = new Specification<TaskEntity>() {
			public Predicate toPredicate(Root<TaskEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate[] pl = new Predicate[3];

				pl[0] = cb.equal(root.get("taskStatus"), TaskStatus.LOCK.getStatus());
				pl[1] = cb.lessThan(root.get("lastUpdate"), DateTime.now().minusMinutes(5).toDate());
				pl[2] = cb.lessThan(root.get("retryCount"), Constants.TASK_MAX_RETRY_COUNT);
				return cb.and(pl);
			}
		};
		Pageable pageable = new PageRequest(0, Constants.HUNDRED_PAGE_SIZE);
		Page<TaskEntity> page = taskRepository.findAll(spec, pageable);
		return page.getContent();
	}

	public List<TaskEntity> getWaitToProcessTaskByTaskType(TaskType taskType) {
		Specification<TaskEntity> spec = new Specification<TaskEntity>() {
			public Predicate toPredicate(Root<TaskEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate[] pl = new Predicate[3];

				pl[0] = cb.equal(root.get("taskType"), taskType.getType());
				pl[1] = cb.equal(root.get("taskStatus"), TaskStatus.INITIALIZE.getStatus());
				pl[2] = cb.lessThan(root.get("bizTime"), Calendar.getInstance().getTime());
				return cb.and(pl);
			}
		};
		Pageable pageable = new PageRequest(0, Constants.HUNDRED_PAGE_SIZE);
		Page<TaskEntity> page = taskRepository.findAll(spec, pageable);
		return page.getContent();
	}
}
